package com.autodesk.akn.emr.services;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.autodesk.akn.emr.dao.S3Dao;
import com.autodesk.akn.emr.dao.StoreDaoMySQL;
import com.autodesk.akn.emr.util.S3Util;

/**
 * 
 * @author jeremias.lopez
 */
@Service
public class S3Service {

	private static final String S3_BUCKET = "s3n://com.autodesk.akn";
	private static final Logger LOGGER = Logger.getLogger(S3Service.class
			.getName());

	@Autowired
	private S3Dao s3Dao;

	@Autowired
	private S3Util s3Util;

	@Autowired
	private StoreDaoMySQL storeDaoMySQL;

	public S3Service() {
	}

	public S3Dao getS3Dao() {
		return s3Dao;
	}

	public void setS3Dao(S3Dao s3Dao) {
		this.s3Dao = s3Dao;
	}

	public S3Util getS3Util() {
		return s3Util;
	}

	public void setS3Util(S3Util s3Util) {
		this.s3Util = s3Util;
	}

	public StoreDaoMySQL getStoreDaoMySQL() {
		return storeDaoMySQL;
	}

	public void setStoreDaoMySQL(StoreDaoMySQL storeDaoMySQL) {
		this.storeDaoMySQL = storeDaoMySQL;
	}

	/**
	 * Get the input log list
	 * 
	 * @return the list of input logs
	 */
	public List<String> getLogPaths() {
		List<String> logs = null;
		List<Bucket> bs = s3Dao.listBuckets();
		if (CollectionUtils.isNotEmpty(bs)) {
			for (Bucket b : bs) {
				if (b.getName().equals("com.autodesk.akn")) {
					ObjectListing result = s3Dao.listObjects(
							"com.autodesk.akn", "akamai_logs/", "/");
					List<S3ObjectSummary> fileList = result
							.getObjectSummaries();
					if (CollectionUtils.isNotEmpty(fileList)) {
						logs = new ArrayList<String>();
						for (S3ObjectSummary o : fileList) {
							if (o.getKey().contains(".gz")) {
							  logs.add(o.getKey());
							}
						}
					}
				}
			}
		}
		return logs;
	}

	/**
	 * Method to load the processed logs into the DB
	 * 
	 * @return a boolean value to indicate the process success
	 */
	public boolean dbLoaderProcess(String processedFile) {
		// Find toDatabase folder and import the results into the DB
		LOGGER.info("dbLoaderProcess");
		List<String> logs = getProcessedLogPaths("ProcessedLogs/");
		for (String log : logs) {
			if (log.contains("toDatabase")) {
				List<String> reportFolders = getProcessedLogPaths(log);
				if (CollectionUtils.isNotEmpty(reportFolders)) {
					for (String folder : reportFolders) {
						LOGGER.info("FOLDER NAME: " + folder);
						List<String> files = getProcessedLogFiles(folder);
						if (CollectionUtils.isNotEmpty(files)) {
							for (String file : files) {
								String reportName = extractFileNameFromPath(file
										.substring(0, file.length()));
								String tableName = extractFileNameFromPath(folder
										.substring(0, folder.length() - 1));
								if (!reportName.equals("*")
										&& !reportName.equals("part-r-00000")
										&& !reportName.equals("_SUCCESS")) {
									String toDatabaseFilePath = s3Util
											.copySingleFileFromS3(
													"com.autodesk.akn", file);
									storeDaoMySQL.storeDataByFile(
											toDatabaseFilePath, tableName);
								}
							}
						}
					}
				}
			}
		}
		// Finally we move the processed log files to StoredLogs directory
		LOGGER.info("moving processed files");
		moveProcessedFiles(processedFile);
		LOGGER.info("processed files moved");
		return true;
	}

	/**
	 * Method to get sub-path list based on a parent path
	 * 
	 * @param path
	 *            The s3 path to find sub-paths
	 * @return the list of sub-paths
	 */
	private List<String> getProcessedLogPaths(String path) {
		List<String> logs = null;
		ObjectListing result = s3Dao.listObjects("com.autodesk.akn", path, "/");
		List<String> fileList = result.getCommonPrefixes();
		if (CollectionUtils.isNotEmpty(fileList)) {
			logs = new ArrayList<String>();
			for (String o : fileList) {
				logs.add(o);
			}
		}
		return logs;
	}

	/**
	 * Method to get the file list inside a s3 path
	 * 
	 * @param path
	 *            The s3 path to find files
	 * @return the list of s3 files
	 */
	private List<String> getProcessedLogFiles(String path) {
		List<String> files = null;
		ObjectListing result = s3Dao.listObjects("com.autodesk.akn", path, "/");
		List<S3ObjectSummary> fileList = result.getObjectSummaries();
		if (CollectionUtils.isNotEmpty(fileList)) {
			files = new ArrayList<String>();
			for (S3ObjectSummary o : fileList) {
				files.add(o.getKey());
			}
		}
		return files;
	}

	/**
	 * Method to extract file name from s3 path
	 * 
	 * @param path
	 *            The s3 path
	 * @return the name of the file
	 */
	public static String extractFileNameFromPath(String path) {
		int idx = path.lastIndexOf('/');
		if (idx > -1) {
			return path.substring(idx + 1);
		} else {
			return path;
		}
	}

	/**
	 * Method to move processed files to definitive folder
	 */
	public void moveProcessedFiles(String processedFile) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String date = sdf.format(Calendar.getInstance().getTime());
		moveExtraInformationFolder(date);
		moveToDatabaseFolder(date);
		moveLogsProcessedFolder(date);
		moveProcessedFile(processedFile, date);
	}

	/**
	 * Move the "logs processed" folder
	 * 
	 * @param date
	 */
	private void moveLogsProcessedFolder(String date) {
		LOGGER.info("start moveLogsProcessedFolder");
		List<String> fileList = this
				.getProcessedLogFiles("ProcessedLogs/LogsProcessed/");
		if (CollectionUtils.isNotEmpty(fileList)) {
			for (String sourceFile : fileList) {
				if (sourceFile.contains(".gz")) {
					String destinyFile = S3_BUCKET
							+ "/"
							+ sourceFile.replace("ProcessedLogs", "StoredLogs/"
									+ date);
					destinyFile = destinyFile + new Date().getTime();
					s3Util.moveFiles(S3_BUCKET + "/" + sourceFile, destinyFile);
				}
			}
		}
		LOGGER.info("end moveLogsProcessedFolder");
	}

	/**
	 * Move the "to database" folder
	 * 
	 * @param date
	 */
	private void moveToDatabaseFolder(String date) {
		LOGGER.info("start moveToDatabaseFolder");
		List<String> fileList = this
				.getProcessedLogPaths("ProcessedLogs/toDatabase/");
		if (CollectionUtils.isNotEmpty(fileList)) {
			for (String path : fileList) {
				for (String sourceFile : this.getProcessedLogFiles(path)) {
					String destinyFile = S3_BUCKET
							+ "/"
							+ sourceFile.replace("ProcessedLogs", "StoredLogs/"
									+ date);
					destinyFile = destinyFile + new Date().getTime();
					s3Util.moveFiles(S3_BUCKET + "/" + sourceFile, destinyFile);
				}
			}
		}
		LOGGER.info("end moveToDatabaseFolder");
	}

	/**
	 * Move the "extra information" folder
	 * 
	 * @param date
	 */
	private void moveExtraInformationFolder(String date) {
		LOGGER.info("start moveExtraInformationFolder");
		List<String> fileList = this
				.getProcessedLogPaths("ProcessedLogs/ExtraInformation/");
		if (CollectionUtils.isNotEmpty(fileList)) {
			for (String path : fileList) {
				for (String sourceFile : this.getProcessedLogFiles(path)) {
					String destinyFile = S3_BUCKET
							+ "/"
							+ sourceFile.replace("ProcessedLogs", "StoredLogs/"
									+ date);
					destinyFile = destinyFile + new Date().getTime();
					s3Util.moveFiles(S3_BUCKET + "/" + sourceFile, destinyFile);
				}
			}
		}
		LOGGER.info("end moveExtraInformationFolder");
	}

	/**
	 * Move the processed file
	 * 
	 * @param source
	 */
	private void moveProcessedFile(String sourceFile, String date) {
		LOGGER.info("start moveProcessedFile");
		String destinyFile = S3_BUCKET
				+ "/"
				+ sourceFile.replace("akamai_logs", "StoredLogs/"
						+ date + "/LogsProcessed");
		s3Util.moveFiles(S3_BUCKET + "/" + sourceFile, destinyFile);
		LOGGER.info("end moveProcessedFile");
	}
}
